import { get, post, put, del } from '@/utils/request'

/**
 * @typedef {Object} PPTDetail
 * @property {string} id - PPT ID
 * @property {string} title - PPT标题
 * @property {string} cover - 封面URL
 * @property {string} createdAt - 创建时间
 * @property {string} updatedAt - 更新时间
 * @property {Array} slides - 幻灯片列表
 */

/**
 * @typedef {Object} UploadResult
 * @property {string} url - 文件URL
 * @property {string} path - 文件路径
 * @property {number} size - 文件大小(字节)
 */

/**
 * @typedef {Object} ExportResult
 * @property {string} url - 导出文件URL
 * @property {string} format - 文件格式
 * @property {number} size - 文件大小(字节)
 */

// 请求重试配置
const RETRY_CONFIG = {
  maxRetries: 3,
  retryDelay: 1000,
  retryOn: [502, 503, 504] // 重试状态码
}

// 请求缓存
const requestCache = new Map()
const CACHE_TTL = 5 * 60 * 1000 // 5分钟缓存

/**
 * 获取PPT列表 (简单版，向后兼容)
 */
export const getPPTListApi = () => getEnhancedPPTList()

/**
 * 增强版PPT列表获取
 * @param {Object} [params={}] - 查询参数
 * @param {boolean} [forceRefresh=false] - 是否强制刷新缓存
 * @returns {Promise<Array<PPTDetail>>}
 */
export const getEnhancedPPTList = (params = {}, forceRefresh = false) => {
  const cacheKey = `list-${JSON.stringify(params)}`
  
  // 检查缓存
  if (!forceRefresh && requestCache.has(cacheKey)) {
    const { data, timestamp } = requestCache.get(cacheKey)
    if (Date.now() - timestamp < CACHE_TTL) {
      return Promise.resolve([...data]) // 返回副本避免污染
    }
  }

  return withRetry(
    () => get('/ppt/list', params),
    RETRY_CONFIG
  )
    .then(data => {
      // 更新缓存
      requestCache.set(cacheKey, {
        data,
        timestamp: Date.now()
      })
      return data
    })
    .catch(handleError)
}

/**
 * 获取PPT详情 (简单版，向后兼容)
 * @param {string} id - PPT ID
 * @returns {Promise<PPTDetail>}
 */
export const getPPTDetailApi = (id) => getEnhancedPPTDetail(id)

/**
 * 增强版PPT详情获取
 * @param {string} id - PPT ID
 * @param {boolean} [forceRefresh=false] - 是否强制刷新缓存
 * @returns {Promise<PPTDetail>}
 */
export const getEnhancedPPTDetail = async (id, forceRefresh = false) => {
  if (!id) {
    throw new Error('PPT ID不能为空')
  }

  // 检查缓存
  if (!forceRefresh && requestCache.has(id)) {
    const { data, timestamp } = requestCache.get(id)
    if (Date.now() - timestamp < CACHE_TTL) {
      return { ...data } // 返回副本避免污染
    }
  }

  try {
    const res = await withRetry(
      () => get(`/ppt/detail/${id}`),
      RETRY_CONFIG
    )
    
    // 更新缓存
    requestCache.set(id, {
      data: res.data,
      timestamp: Date.now()
    })
    
    return res.data
  } catch (error) {
    handleError(error)
    throw error // 重新抛出以保持错误传播
  }
}

// 创建PPT
export const createPPTApi = (pptData) => {
  return post('/ppt/create', pptData)
}

// 更新PPT
export const updatePPTApi = (pptData) => {
  return put(`/ppt/update/${pptData.id}`, pptData)
}

// 删除PPT
export const deletePPTApi = (id) => {
  return del(`/ppt/delete/${id}`)
}

// 错误类型映射
const ERROR_MAP = {
  'Network Error': '网络连接失败',
  'Request failed with status code 401': '未授权，请重新登录',
  'Request failed with status code 404': '资源不存在',
  'Request failed with status code 500': '服务器错误'
}

// 统一错误处理
const handleError = (error) => {
  let errMsg = error.message || '请求失败'
  
  // 映射已知错误
  if (error.response) {
    const status = error.response.status
    if (status === 401) {
      // 触发重新登录
      uni.navigateTo({ url: '/pages/login/login' })
    }
    errMsg = ERROR_MAP[error.message] || `请求失败: ${status}`
  }
  
  // 显示错误提示
  uni.showToast({
    title: errMsg,
    icon: 'none',
    duration: 3000
  })
  
  // 抛出处理后的错误
  throw new Error(errMsg)
}

// 计算文件MD5 (简单实现，实际项目应使用更可靠的库)
const calculateFileMd5 = (file) => {
  return new Promise((resolve) => {
    // 这里简化实现，实际项目应使用spark-md5等库
    const reader = new FileReader()
    reader.onload = (e) => {
      const hash = Array.prototype.map.call(
        new Uint8Array(e.target.result),
        byte => byte.toString(16).padStart(2, '0')
      ).join('')
      resolve(hash)
    }
    reader.readAsArrayBuffer(file)
  })
}

// 允许的封面图片类型
const ALLOWED_COVER_TYPES = ['image/jpeg', 'image/png', 'image/webp']

// 上传错误代码映射
const UPLOAD_ERRORS = {
  '文件不存在': 'FILE_NOT_FOUND',
  '文件类型不支持': 'INVALID_FILE_TYPE',
  '文件过大': 'FILE_TOO_LARGE',
  '上传失败': 'UPLOAD_FAILED'
}

// 请求重试封装
const withRetry = async (requestFn, config = {}) => {
  const { maxRetries = 3, retryDelay = 1000 } = config
  let retryCount = 0
  
  while (retryCount < maxRetries) {
    try {
      return await requestFn()
    } catch (error) {
      if (!config.retryOn || !config.retryOn.includes(error.response?.status)) {
        throw error
      }
      retryCount++
      if (retryCount < maxRetries) {
        await new Promise(resolve => setTimeout(resolve, retryDelay))
      } else {
        throw error
      }
    }
  }
}

/**
 * 上传PPT封面图片
 * @param {string} filePath - 图片文件路径
 * @param {string} pptId - PPT ID
 * @param {Function} [onProgress] - 上传进度回调
 * @param {number} [maxRetries=3] - 最大重试次数
 * @returns {Promise<UploadResult>}
 */
export const uploadPPTCoverApi = (filePath, pptId, onProgress, maxRetries = 3) => {
  return new Promise(async (resolve, reject) => {
    let retryCount = 0
    let fileMd5 = ''
    
    const doUpload = async () => {
      try {
        // 获取文件信息
        const fileInfo = await new Promise((res, rej) => {
          uni.getFileInfo({
            filePath,
            success: res,
            fail: rej
          })
        })

        // 验证文件大小(不超过5MB)
        if (fileInfo.size > 5 * 1024 * 1024) {
          throw new Error(UPLOAD_ERRORS['文件过大'])
        }

        // 计算文件MD5
        const fileContent = await new Promise((res, rej) => {
          uni.getFileSystemManager().readFile({
            filePath,
            success: res,
            fail: rej
          })
        })
        
        // 验证文件类型
        const fileType = fileContent.data.type || ''
        if (!ALLOWED_COVER_TYPES.includes(fileType)) {
          throw new Error(UPLOAD_ERRORS['文件类型不支持'])
        }

        // 计算MD5 (简化版)
        fileMd5 = Array.prototype.map.call(
          new Uint8Array(fileContent.data),
          byte => byte.toString(16).padStart(2, '0')
        ).join('').slice(0, 32)

        // 执行上传
        const uploadResult = await new Promise((res, rej) => {
          const uploadTask = uni.uploadFile({
            url: '/ppt/upload-cover',
            filePath,
            name: 'file',
            formData: { 
              pptId,
              fileMd5,
              fileSize: fileInfo.size
            },
            success: (result) => {
              if (result.statusCode === 200) {
                res(JSON.parse(result.data))
              } else {
                rej(new Error(result.errMsg))
              }
            },
            fail: rej
          })

          // 进度回调
          if (onProgress) {
            uploadTask.onProgressUpdate((progress) => {
              onProgress(progress.progress)
            })
          }
        })

        resolve(uploadResult)
      } catch (error) {
        if (retryCount < maxRetries) {
          retryCount++
          console.warn(`上传失败，第${retryCount}次重试...`)
          await new Promise(r => setTimeout(r, 1000 * retryCount))
          return doUpload()
        }
        reject(handleError(error))
      }
    }

    await doUpload()
  })
}

// 导出PPT
export const exportPPTApi = (id, format = 'pdf') => {
  return get(`/ppt/export/${id}`, { format })
}

// API使用示例
/*
// 获取PPT列表 (带缓存)
getEnhancedPPTList({ page: 1, size: 10 })
  .then(list => console.log('PPT列表:', list))

// 获取PPT详情 (强制刷新)
getEnhancedPPTDetail('123', true)
  .then(detail => console.log('PPT详情:', detail))

// 上传封面 (带进度和重试)
uploadPPTCoverApi('path/to/image.jpg', 'ppt123', (progress) => {
  console.log(`上传进度: ${progress}%`)
})
*/

// 性能监控标记
const perfMark = (name) => {
  if (typeof performance !== 'undefined') {
    performance.mark(`api-${name}-start`)
  }
}

const perfMeasure = (name) => {
  if (typeof performance !== 'undefined') {
    performance.mark(`api-${name}-end`)
    performance.measure(
      `api-${name}`,
      `api-${name}-start`,
      `api-${name}-end`
    )
  }
}

// 导出工具函数
export {
  withRetry,
  handleError,
  calculateFileMd5
}